const WebSocket = require('ws')
const WebSocketModel = require('../../db/model/WebSocketModel')
const { to } = require('await-to-js')
const { getQueryObject } = require('../index')

let clients = {}

const startWebSocketMonitor = () => {
    const ws = new WebSocket.Server({ port: 9998 }, () => {
        //启动心跳
        heartbeat(60)
    })

    ws.on('connection', async (client, req) => {
        client.id = getId()
        client.lastTime = parseInt(new Date().getTime() / 1000)
        let { secret } = getQueryObject(req.url)

        //获取数据库中的记录
        let [err, record] = await to(getRecord(secret))
        if (err) console.log(err)
        if (!record) {
            client.send(JSON.stringify({ code: 1, msg: '未开启监控或密钥错误' }))
            client.close()
            return
        }

        if (!clients[secret]) clients[secret] = []
        //添加客户端到内存中
        clients[secret].push(client)
        //更新数据库的连接数
        await to(updateConnection(secret, clients[secret].length))

        client.on('close', () => { })
        client.on('message', (data) => {
            const {code} = JSON.parse(data)
            //999客户端发送的心跳
            if(code === 999) client.lastTime = parseInt(new Date().getTime() / 1000)
        })
    })
}

//服务端心跳检测
const heartbeat = (s) => {
    setInterval(async () => {
        let now = parseInt(new Date().getTime() / 1000)
        for (let prop in clients) {
            clients[prop].forEach((client, index) => {
                if (now - s > client.lastTime) {
                    client.send(JSON.stringify({ code: 1, msg: '心跳过期' }))
                    client.close()
                    //清除内存中的客户端
                    clients[prop].splice(index, 1);
                }
            })
            //更新连接数
            await to(updateConnection(prop, clients[prop].length))
        }
    }, s * 1000)
}

const getRecord = (secret) => {
    return new Promise((resolve, reject) => {
        WebSocketModel.findOne({ secret, status: 1 }).then(result => {
            resolve(result)
        }).catch(err => {
            console.log(err)
            reject(null)
        })
    })
}

const updateConnection = (secret, num) => {
    return new Promise((resolve, reject) => {
        WebSocketModel.updateOne({ secret }, { num }).then(result => {
            resolve(result)
        }).catch(err => {
            console.log(err)
            reject(err)
        })
    })
}

const getId =  (() => {
    let id = 0
    return  () => {
        id++
        return id
    }
})()



//暴露通知刷新客户端方法
const refresh = (secret) => {
    let clientArr = clients[secret] || []
    clientArr.forEach(client => {
        client.send(JSON.stringify({ code: 666, msg: '有新的版本发布,请刷新页面' }))
    })
}

module.exports = {
    startWebSocketMonitor, refresh
}





